/*****************************************************************************
 * air720.c
 *
 * Copyright (C) 2020 Jeasonvor 1101627719@qq.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 ****************************************************************************/

/*****************************************************************************
 * Included Files
 ****************************************************************************/
#include "plum_api.h"
#include "hardware/cat1/cat1.h"
/*****************************************************************************
 * Trace Definitions
 ****************************************************************************/
#define LOG_RUN_LEVEL LOG_LEVEL_DEBUG
#define LOG_MODULE    "dev.air720"
#include "thirdparty/log/log.h"
/*****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/
#define DEV_AIR720_UART         PLUM_HAL_UART_ID(1)
#define DEV_AIR720_UART_TIMEOUT 1000
#define DEV_AIR720_UART_TX_MAX  1024
#define DEV_AIR720_UART_RX_MAX  1024
#define DEV_MODULE_NAME         "AIR720"
/*****************************************************************************
 * Private Types
 ****************************************************************************/

typedef enum {
    MQTT_MODE_ASCII,
    MQTT_MODE_HEX,
} air720_mqtt_mode_t;

typedef enum {
    CREG_STA_UNREGISTER,
    CREG_STA_REGISTERED,
    CREG_STA_UNREGISTER_SERCHING,
} air720_creg_sta_t;

typedef enum {
    CREG_URC_DISABLE,
    CREG_URC_ENABLE,
    CREG_URC_LOCAL_ENABLE,
} air720_creg_urc_t;

typedef enum {
    CGATT_SPLIT,
    CGATT_ATTACH,
} air720_cgatt_t;
/*****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/

/*****************************************************************************
 * Private Data
 ****************************************************************************/

/*****************************************************************************
 * Public Data
 ****************************************************************************/

/*****************************************************************************
 * Private Functions
 ****************************************************************************/

PLUM_PRIVATE
plum_s32 air720_power_on(plum_void)
{
    plum_s32 rc = PLUM_ECODE_OK;

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_power_off(plum_void)
{
    plum_s32 rc = PLUM_ECODE_OK;

    return (rc);
}

PLUM_PRIVATE
plum_void air720_uart_baudrate_adapter(plum_void)
{
    plum_s8 cmd[]                        = "AT\r\n";
    plum_s8 text[DEV_AIR720_UART_RX_MAX] = {0};

    do {
        plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        plum_kal_thread_delay(500);

        memset(text, 0, sizeof(text));
        plum_hal_uart_recv(DEV_AIR720_UART, cmd, sizeof(cmd), 0);
        plum_kal_thread_delay(500);
    } while (strstr((char *)text, "OK") != NULL);
}

PLUM_PRIVATE
plum_s32 air720_reset(plum_void)
{
    plum_s32 rc = PLUM_ECODE_OK;

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_ate(plum_bit sta)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[DEV_AIR720_UART_TX_MAX] = {0};
        snprintf(cmd, sizeof(cmd), "AT+ATE%d\r\n", sta);

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            if (strstr(recv, "OK")) {
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_creg_get(air720_creg_sta_t *creg)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[] = "AT+CREG?\r\n";

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            char *ptr = strstr(recv, "+CRGE:");
            if (ptr) {
                sscanf(ptr, "+CRGE:%d", (int *)creg);
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_creg_set(air720_creg_urc_t urc)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[DEV_AIR720_UART_TX_MAX] = {0};
        snprintf(cmd, sizeof(cmd), "AT+CREG=%d\r\n", urc);

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            if (strstr(recv, "OK")) {
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_cgatt_get(air720_cgatt_t *cgatt)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[] = "AT+CGATT?\r\n";

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            char *ptr = strstr(recv, "+CGATT:");
            if (ptr) {
                sscanf(recv, "+CGATT:%d", (int *)cgatt);
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_cgatt_set(air720_cgatt_t cgatt)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[DEV_AIR720_UART_TX_MAX] = {0};
        snprintf(cmd, sizeof(cmd), "AT+CGATT=%d\r\n", cgatt);

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            if (strstr(recv, "OK")) {
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_imei_get(plum_s8 *imei)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[] = "AT+CGSN\r\n";

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            char *ptr = strstr(recv, "OK");
            if (ptr) {
                snprintf((char *)imei, 16, "%s", recv);
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_csq_get(plum_u8 *rssi)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[] = "AT+CSQ\r\n";

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            char *ptr = strstr(recv, "+CSQ:");
            if (ptr) {
                int ber = 0;
                sscanf(ptr, "+CSQ:%d,%d", (int *)rssi, &ber);
                LOG_I("RSSI : %d,BER : %d", ber);
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_mqttmode(air720_mqtt_mode_t mode)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[DEV_AIR720_UART_TX_MAX] = {0};
        snprintf(cmd, sizeof(cmd), "AT+MQTTMODE=%d\r\n", mode);

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            if (strstr(recv, "OK")) {
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_mconfig(plum_s8 *clientid, plum_s8 *username, plum_s8 *passwd)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[DEV_AIR720_UART_TX_MAX] = {0};
        snprintf(cmd, sizeof(cmd), "AT+MCONFIG=%s,%s,%s", clientid, username,
                 passwd);

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, strlen(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(recv),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            if (strstr(recv, "OK")) {
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }

    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_mipstart(plum_s8 *url, plum_s32 port)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[DEV_AIR720_UART_TX_MAX] = {0};
        snprintf(cmd, sizeof(cmd), "AT+MIPSTART=%s,%d\r\n", url, port);

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            if (strstr(recv, "OK")) {
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s8 air720_mconnect(plum_void)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[DEV_AIR720_UART_TX_MAX] = "AT+MCONNECT=0,600\r\n";

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            if (strstr(recv, "OK")) {
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_mpub(plum_s8 *topic, plum_u8 qos, plum_s8 *msg)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[DEV_AIR720_UART_TX_MAX] = {0};
        snprintf(cmd, sizeof(cmd), "AT+MPUB=%s,%d,1,%s", topic, qos, msg);

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            if (strstr(recv, "OK")) {
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 air720_msub(plum_s8 *topic)
{
    plum_s32 rc = PLUM_ECODE_OK;

    do {
        char cmd[DEV_AIR720_UART_TX_MAX] = {0};
        snprintf(cmd, sizeof(cmd), "AT+MSUB=%s,0", topic);

        LOG_D("%s TX: %s", DEV_MODULE_NAME, cmd);
        rc = plum_hal_uart_send(DEV_AIR720_UART, cmd, sizeof(cmd));
        if (rc) {
            LOG_E("plum_hal_uart_send err,rc:%d", rc);
            break;
        }

        char recv[DEV_AIR720_UART_RX_MAX] = {0};
        rc = plum_hal_uart_recv(DEV_AIR720_UART, recv, sizeof(cmd),
                                DEV_AIR720_UART_TIMEOUT);
        LOG_D("%s RX: %s", DEV_MODULE_NAME, recv);
        if (rc > 0) {
            if (strstr(recv, "OK")) {
                rc = PLUM_ECODE_OK;
            }
            else {
                rc = PLUM_ECODE_UNK;
            }
        }
        else {
            rc = PLUM_ECODE_TIMEOUT;
        }
    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 dev_air720_init(plum_device_ref_t dev)
{
    PLUM_UNUSED(dev);
    plum_s32 rc = PLUM_ECODE_OK;

    LOG_D("dev_air720_init");
    do {
        rc = air720_power_on();
        if (rc) {
            LOG_E("air720_power_on err,rc:%d", rc);
            break;
        }

        air720_uart_baudrate_adapter();

        rc = air720_ate(plum_false);
        if (rc) {
            LOG_E("air720_ate err,rc:%d", rc);
            break;
        }

    } while (0);

    return (rc);
}

PLUM_PRIVATE
plum_s32 dev_air720_fini(plum_device_ref_t dev)
{
    plum_s32 rc = PLUM_ECODE_OK;

    PLUM_UNUSED(dev);

    return (rc);
}

PLUM_PRIVATE
plum_s32 dev_air720_reset(plum_device_ref_t dev)
{
    plum_s32 rc = PLUM_ECODE_OK;

    PLUM_UNUSED(dev);

    return (rc);
}

PLUM_PRIVATE
plum_s32 dev_air720_setpm(plum_device_ref_t dev, plum_dev_pm_t pm)
{
    PLUM_UNUSED(dev);
    plum_s32 rc = PLUM_ECODE_OK;

    PLUM_UNUSED(dev);
    switch (pm) {
        case PLUM_DEV_PM_OFF:
            LOG_I("PLUM_DEV_PM_OFF");
            break;
        case PLUM_DEV_PM_ON:
            LOG_I("PLUM_DEV_PM_ON");
            break;
        case PLUM_DEV_PM_SLEEP:
            LOG_I("PLUM_DEV_PM_SLEEP");
            break;
        case PLUM_DEV_PM_WAKEUP:
            LOG_I("PLUM_DEV_PM_WAKEUP");
            break;
        default:
            LOG_E("Not Support The Power Mode");
            break;
    }

    return (rc);
}

PLUM_PRIVATE
plum_s32 dev_air720_read(plum_device_ref_t dev, plum_dev_read_t *arg)
{
    plum_s32 rc = PLUM_ECODE_OK;

    PLUM_UNUSED(dev);
    PLUM_UNUSED(arg);

    return (rc);
}

PLUM_PRIVATE
plum_s32 dev_air720_write(plum_device_ref_t dev, plum_dev_write_t *arg)
{
    plum_s32 rc = PLUM_ECODE_OK;

    PLUM_UNUSED(dev);
    PLUM_UNUSED(arg);

    return (rc);
}

PLUM_PRIVATE
plum_s32 dev_air720_ioctl(plum_device_ref_t dev, plum_u32 ctrl_id,
                          plum_void *arg)
{
    PLUM_UNUSED(dev);
    plum_s32 rc = PLUM_ECODE_OK;

    switch (ctrl_id) {
        case PLUM_MQTT_IOCTL_CON:
            LOG_D("PLUM_MQTT_IOCTL_CON");
            break;
        case PLUM_MQTT_IOCTL_DISCON:
            LOG_D("PLUM_MQTT_IOCTL_DISCON");
            break;
        case PLUM_MQTT_IOCTL_PUB:
            LOG_D("PLUM_MQTT_IOCTL_PUB");
            break;
        case PLUM_MQTT_IOCTL_SUB:
            LOG_D("PLUM_MQTT_IOCTL_SUB");
            break;
        case PLUM_MQTT_IOCTL_UNSUB:
            LOG_D("PLUM_MQTT_IOCTL_UNSUB");
            break;
        case PLUM_MQTT_IOCTL_MSG_CB:
            LOG_D("PLUM_MQTT_IOCTL_MSG_CB");
            break;
        case PLUM_MQTT_IOCTL_YIELD:
            LOG_D("PLUM_MQTT_IOCTL_YIELD");
            break;
        default:
            LOG_E("not support the ctl id,%d", ctrl_id);
            break;
    }

    return (rc);
}

/*****************************************************************************
 * Public Functions
 ****************************************************************************/

PLUM_PRIVATE plum_dev_api_t air720_api = {.init   = dev_air720_init,
                                          .fini   = dev_air720_fini,
                                          .reset  = dev_air720_reset,
                                          .setpm  = dev_air720_setpm,
                                          .read   = dev_air720_read,
                                          .write  = dev_air720_write,
                                          .ioctrl = dev_air720_ioctl};

PLUM_DEVICE_EXPORT(luat_air720, &air720_api);

/****************************************************************************/
/*                                                                          */
/*  End of file.                                                            */
/*                                                                          */
/****************************************************************************/
